package com.doudou.collection.domain.service.admin.impl;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.IdUtil;
import com.doudou.collection.domain.service.admin.LoginService;
import com.doudou.collection.infrastructure.common.ex.ServiceException;
import com.doudou.collection.infrastructure.common.web.StatusCode;
import com.doudou.collection.infrastructure.core.security.CustomUserDetails;
import com.doudou.collection.infrastructure.core.service.TokenService;
import com.doudou.collection.orm.dto.admin.login.LoginDTO;
import com.doudou.collection.orm.vo.UserLoginSimpleVO;
import com.doudou.collection.orm.vo.admin.ImageCodeVO;
import com.doudou.collection.utils.redis.RedisConstants;
import com.google.code.kaptcha.Producer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.util.FastByteArrayOutputStream;

import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName LoginServiceImpl<br>
 * @Description 管理员业务逻辑层实现类<br>
 * @Author 李浩文<br>
 * @Date 2023/6/20 19:58<br>
 * @Version 1.0<br>
 */
@Slf4j
@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    private AuthenticationManager manager;

    @Autowired
    private StringRedisTemplate redisCache;

    @Resource(name = "captchaProducer")
    private Producer captchaProducer;

    @Resource(name = "captchaProducerMath")
    private Producer captchaProducerMath;

    @Autowired
    private TokenService tokenService;

    @Override
    public UserLoginSimpleVO login(LoginDTO loginDTO) {
        log.debug("正在执行【管理员登陆】业务逻辑，参数：{}", loginDTO);

        // 从redis中获取对应的验证码
        String captcha = redisCache.opsForValue().get(RedisConstants.CAPTCHA_CODE_KEY + loginDTO.getUuid());
        redisCache.delete(RedisConstants.CAPTCHA_CODE_KEY + loginDTO.getUuid());
        if (captcha == null) {
            String message = "登陆失败, 验证码已过期！";
            log.debug(message);
            throw new ServiceException(StatusCode.FAILED.getCode(), message);
        }
        if (!captcha.equals(loginDTO.getCode())) {
            log.debug(StatusCode.CODE_ERROR.getMessage());
            throw new ServiceException(StatusCode.CODE_ERROR);
        }

        // 验证码比对完成 开启登录认证流程
        Authentication result = manager.authenticate(new UsernamePasswordAuthenticationToken(
                loginDTO.getUsername(),
                loginDTO.getPassword()
        ));

        CustomUserDetails userDetails = (CustomUserDetails) result.getPrincipal();
        log.debug("CustomUserDetails: {}", userDetails);
        String token = tokenService.createToken(userDetails);

        UserLoginSimpleVO loginSimpleVO = new UserLoginSimpleVO()
                .setId(userDetails.getId())
                .setUsername(userDetails.getUsername())
                .setIcon(userDetails.getIcon())
                .setToken(token);
        log.debug("UserLoginSimpleVO: {}", loginSimpleVO);
        return loginSimpleVO;
    }

    @Override
    public ImageCodeVO generateCaptchaImg() {
        //保存验证码信息
        String uuid = IdUtil.simpleUUID();
        String verifyKey = RedisConstants.CAPTCHA_CODE_KEY + uuid;

        String capText = captchaProducerMath.createText();
        String capStr = capText.substring(0, capText.lastIndexOf("@"));
        String code = capText.substring(capText.lastIndexOf("@") + 1);
        BufferedImage image = captchaProducerMath.createImage(capStr);

        // 转换流信息写出
        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        ImgUtil.writeJpg(image, os);

        redisCache.opsForValue().set(verifyKey, code, RedisConstants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);


        ImageCodeVO imageCode = new ImageCodeVO();
        imageCode.setIsCaptchaEnabled(true);
        imageCode.setImg(Base64.encode(os.toByteArray()));
        imageCode.setUuid(uuid);
        return imageCode;
    }
}
